package com.dlc.shop.api.controller;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.huifu.bspay.sdk.opps.core.request.V2TradeOnlinepaymentUnionpayRequest;
import com.huifu.bspay.sdk.opps.core.request.V2TradePaymentJspayRequest;
import com.huifu.bspay.sdk.opps.core.utils.DateTools;
import com.huifu.bspay.sdk.opps.core.utils.SequenceTools;
import com.dlc.shop.api.huifu.OppsMerchantConfigDemo;
import com.dlc.shop.bean.app.param.PayParam;
import com.dlc.shop.bean.bo.PayInfoResultBO;
import com.dlc.shop.bean.model.*;
import com.dlc.shop.bean.pay.PayInfoDto;
import com.dlc.shop.common.exception.YamiShopBindException;
import com.dlc.shop.common.response.ResponseEnum;
import com.dlc.shop.common.response.ServerResponseEntity;
import com.dlc.shop.common.util.ExceptionUtils;
import com.dlc.shop.common.util.IpHelper;
import com.dlc.shop.config.ShopConfig;
import com.dlc.shop.huifu.DemoTestConstants;
import com.dlc.shop.security.common.bo.LoginInfoBO;
import com.dlc.shop.security.common.manager.TokenStore;
import com.dlc.shop.service.*;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.servlet.http.HttpServletRequest;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

import static com.dlc.shop.api.huifu.BaseCommonDemo.doExecute;
import static com.dlc.shop.api.huifu.BaseCommonDemo.doInit;

/**
 * 汇付天下 云闪付支付
 */
@RestController
@RequestMapping("/huifu/yunpay")
@AllArgsConstructor
@Slf4j
public class HuifuYunPayController {

    private final OrderService orderService;
    private final ShopDetailService shopDetailService;
    private final SkuService skuService;
    private final OrderItemService orderItemService;
    private final TokenStore tokenStore;
    private final PayInfoService payInfoService;
    private final ShopConfig shopConfig;

    @PostMapping("/getQrCode")
    @Transactional(rollbackFor = Exception.class)
    public ServerResponseEntity callback(@RequestBody PayParam payParam) throws Exception{

        List<Order> orderList = orderService.list(new LambdaQueryWrapper<Order>()
                .in(Order::getOrderNumber, payParam.getOrderNumbers().split(StrUtil.COMMA)));
        if(orderList.size() <= 0) {
            return ServerResponseEntity.fail(ResponseEnum.SHOW_FAIL,"订单信息不存在");
        }
        String userId = orderList.get(0).getUserId();
        String bizUserId = null;
        LoginInfoBO loginInfo = tokenStore.getLoginInfoByCache();
        if (loginInfo!=null) {
            bizUserId = loginInfo.getBizUserId();
        }

        PayInfoDto payInfo = payInfoService.pay(userId, payParam,null, bizUserId);

        // 1. 数据初始化
        doInit(OppsMerchantConfigDemo.getMerchantConfig());

        // 2.组装请求参数
        V2TradeOnlinepaymentUnionpayRequest request = new V2TradeOnlinepaymentUnionpayRequest();
        // 请求日期
        request.setReqDate(DateTools.getCurrentDateYYYYMMDD());
        // 请求流水号
        request.setReqSeqId(SequenceTools.getReqSeqId32());
        // 商户号
        request.setHuifuId(DemoTestConstants.DEMO_SYS_ID);
        // 商品描述
        request.setOrderDesc(orderList.stream().map(Order::getProdName).collect(Collectors.joining(",")));
        // 交易金额
        request.setTransAmt(String.format("%.2f",  orderList.stream().mapToDouble(Order::getActualTotal).sum()));
        // 三方支付数据jsonObject；pay_scene为云闪付公众号与云闪付小程序时必填
        request.setThirdPayData(getThirdPayData());
        // 安全信息
        request.setRiskCheckData(getRiskCheckData());

        // 设置非必填字段
        Map<String, Object> extendInfoMap = getExtendInfos(orderList);
        request.setExtendInfo(extendInfoMap);

        // 3. 发起API调用
        Map<String, Object> responseRes = doExecute(request);
        log.info("返回数据:" + JSONObject.toJSONString(responseRes));
        try {
            if(!responseRes.get("trans_stat").equals("F")){
                QueryWrapper<PayInfo> queryWrapper = new QueryWrapper();
                queryWrapper.lambda().eq(PayInfo::getPayNo, payInfo.getPayNo());
                PayInfo finalPayInfo = payInfoService.getOne(queryWrapper);
                finalPayInfo.setBizPayNo(request.getReqSeqId());
                finalPayInfo.setReqDate(request.getReqDate());
                payInfoService.update(finalPayInfo, new LambdaUpdateWrapper<PayInfo>().eq(PayInfo::getPayNo, finalPayInfo.getPayNo()));
                return ServerResponseEntity.success(responseRes.get("qr_code").toString());
            }else {
                throw new RuntimeException(responseRes.get("resp_desc").toString());
            }
        }  catch (RuntimeException e) {
            log.info("汇付信息保存失败:"+ ExceptionUtils.getRunException(e));
            return ServerResponseEntity.fail(ResponseEnum.SHOW_FAIL,e.getMessage());
        }
    }

    private  Map<String, Object> getExtendInfos(List<Order> orderList) throws ParseException {
        // 设置非必填字段
        Map<String, Object> extendInfoMap = new HashMap<>();
        // 卡号锁定标识
        //extendInfoMap.put("card_number_lock", "");
        // 直通模式的银行标识
        //extendInfoMap.put("ebank_en_abbr", "");
        // 交易银行卡卡号
        //extendInfoMap.put("pay_card_no", "");
        // 支付卡类型
        //extendInfoMap.put("pay_card_type", "C");
        // 订单失效时间
        //extendInfoMap.put("time_expire", "");
        // 分账对象
        //extendInfoMap.put("acct_split_bunch", getAcctSplitBunch(orderList));
        // 前端跳转地址
        //extendInfoMap.put("front_url", "");
        // 备注
        //extendInfoMap.put("remark", "");
        // 支付场景
        extendInfoMap.put("pay_scene", "U_JSAPI");
        // 异步通知地址
        extendInfoMap.put("notify_url", shopConfig.getDomain().getApiDomainName()+"/huifu/alipay/huiFuCallback");
        return extendInfoMap;
    }

    private  String getAcctSplitBunch(List<Order> orderList) {
        JSONObject dto = new JSONObject();
        // 分账明细
        dto.put("acct_infos", getAcctInfosRucan(orderList));

        return dto.toJSONString();
    }
    private  JSON getAcctInfosRucan(List<Order> orderList) {
        Double totalMoney = 0d;
        JSONArray dtoList = new JSONArray();
        for (Order order : orderList) {
            ShopDetail shopDetail = shopDetailService.getById(order.getShopId());
            if(Objects.isNull(shopDetail.getHuifuId())){
                //如果汇付 id 为null 的情况下告诉页面  拉起二维码失败
                throw  new YamiShopBindException("支付拉起失败,请联系平台客服！");
            }
            if(shopDetail.getHuifuId().equals(DemoTestConstants.DEMO_SYS_ID)) {
                continue;
            }
            double aDouble = 0d;
            List<OrderItem> orderItems = orderItemService.getOrderItemsByOrderNumber(order.getOrderNumber(), false);
            for (OrderItem orderItem : orderItems) {
                Sku sku = skuService.getSkuBySkuId(orderItem.getSkuId());
                aDouble += (sku.getSupplierPrice() * orderItem.getProdCount());
            }

            JSONObject dto = new JSONObject();
            // 分账金额
            dto.put("div_amt", BigDecimal.valueOf(aDouble).setScale(2, RoundingMode.HALF_UP));
            // 分账接收方ID
            dto.put("huifu_id", shopDetail.getHuifuId());
            dtoList.add(dto);
            totalMoney += aDouble;
        }

        Double sumActualTotal = orderList.stream().mapToDouble(Order::getActualTotal).sum();


        JSONObject dto1 = new JSONObject();
        dto1.put("div_amt", BigDecimal.valueOf(sumActualTotal - totalMoney).setScale(2, RoundingMode.HALF_UP));
        // 分账接收方ID
        dto1.put("huifu_id", DemoTestConstants.DEMO_SYS_ID);
        dtoList.add(dto1);
        return dtoList;
    }

    private static String getThirdPayData() {
        JSONObject dto = new JSONObject();
        // 小程序id
        dto.put("app_id", "wx9055898cfd96a3f2");

        return dto.toJSONString();
    }

    private static String getRiskCheckData() {
        JSONObject dto = new JSONObject();
        // 基站地址
        //dto.put("base_station", "7");
        // ip地址
         dto.put("ip_addr", IpHelper.getIpAddr());
        // 纬度
        //dto.put("latitude", "4");
        // 经度
        //dto.put("longitude", "3");

        return dto.toJSONString();
    }

    @PostMapping("/huiFuCallback")
    @Operation(summary = "汇付回调")
    public String huiFuCallback(HttpServletRequest request){
            String respCode = request.getParameter("resp_code");;
            JSONObject respData = JSONObject.parseObject(request.getParameter("resp_data"));
            log.info("汇付回调返回报文-------------------------："+respData.toString());
            PayInfo payInfo = payInfoService.getOne(new LambdaQueryWrapper<PayInfo>()
                    .eq(PayInfo::getBizPayNo, respData.get("req_seq_id").toString()));

            if(payInfo == null){
                return "";
            }

            if(respCode.equals("00000000") && respData.get("trans_stat").equals("S")){

                PayInfoResultBO payInfoResultBO = new PayInfoResultBO();
                payInfoResultBO.setPayNo(payInfo.getPayNo());
                payInfoResultBO.setBizPayNo(respData.get("req_seq_id").toString());
                payInfoResultBO.setIsPaySuccess(true);
                payInfoResultBO.setPayAmount(Double.valueOf(respData.get("trans_amt").toString()));
                payInfoResultBO.setCallbackContent(respData.toString());

                payInfoService.noticeOrder(payInfoResultBO, payInfo,0);

                return "RECV_ORD_ID_" + respData.get("req_seq_id").toString();
            }
        return "";
    }
}

